home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
lisp
/
eulisp
/
mpfeel.lha
/
MPFeel
/
Plurals
/
mp_gc.m
< prev
next >
Wrap
Text File
|
1992-06-03
|
18KB
|
613 lines
/*
* Plurals
*
* Author: S.C.Merrall
*
* File: mp_gc.m
*
* Contents: heap_alloc
* mp_alloc
* test
* eq
* copy
* mp_gc
* gc
*
* Description: Allocation and garbage collection of heap objects
* works with the same memory as mp_mem_mgmt uses but
* the garbage collection processes are different.
*
* Change History:
*
* Date Name Comment
* -------- ---- -------
* 16:04:91 SCM Created
* 22:04:91 SCM Uses MasPar Plural Heap objects instead of offsets
* 15:05:91 SCM heap_alloc takes space as multiple of 16-bits not 32
* 16:06:91 SCM mp_alloc transferred from mp_alloc.m
* 04:06:91 SCM Sizes in bytes, plus alignment
* 26:01:92 SCM Added some GC code
* 02:02:92 SCM Made eq work properly and cope with symbols
* 06:04:92 SCM Clever hack for nullp in test wont work as NIL changed
*
*/
#include <mpl.h>
#include <stdio.h>
#include "proc_pair.h"
#include "constant.h"
#include "mp_utils.h"
#include "mp_object.h"
#include "mp_debug_off.h"
#include "mp_mem_mgmt.h"
#include "mp_type.h"
#include "mp_gc.h"
#define SDEBUG(x) DO_DEBUG(x)
char *gc_message; /* Used to indicate what function caused the GC */
plural natural *gc_roots[MAX_GC_ROOTS+1];
int next_gc_root = 0;
/* Scratch Space: same ammount of memory on each processor, used for message
* passing and printing */
char acu_scratch[SCRATCH_MEMORY_SIZE];
visible plural char scratch[SCRATCH_MEMORY_SIZE];
/* This array contains the size of a given object under its identifier */
#define TYPE_SIZE 0
#define TYPE_ALIGN 1
int type_info_table[NUMBER_OF_TYPES][2] = { NULL, NULL,
INTEGER_SIZE, INTEGER_ALIGN,
MP_CONS_SIZE, MP_CONS_ALIGN,
MP_VECTOR_SIZE, MP_VECTOR_ALIGN,
MP_FLOAT_SIZE, MP_FLOAT_ALIGN,
MP_SYMBOL_SIZE, MP_SYMBOL_ALIGN};
/*
* Each processors heap space can be grabage collected by mark and sweep
* the marking is done by tracing through the heap space from the pointers
* in the plural space. Garbage collection will be fired when heap_alloc
* fails, if GC fails to claim sufficient space, a global garbage collection
* can be forced and another local garbage collection attempted. If that fails
* to a reorganisation of the array may be able to make space available
*/
/*----------------------------------------------------------------------------*
* Function : heap_alloc
*
* Parameters : plural int space: How much memory we want
* allocated on each active
* processor. (in bytes)
* plural int type: the types of the things
* were allocating space for
* MP_PluralHeap MPPH_var: MP_PluralHeap object, handle
* the plural heap objects.
*
* Description: Allocates the requested ammount of memory on each active
* processor. If one processor fails the whole operation fails.
* The allocated space is aligned if appropriate, this may
* cause gaps in the heap, these are filled with null objects
* of the appropriate size.
*
* Result : int: SUCCESS/FAIL
*---------------------------------------------------------------------------*/
#ifdef __STDC__
int heap_alloc( plural int space, plural int type, MP_PluralHeap MPPH_var )
#else
int heap_alloc( space, type, MPPH_var )
plural int space;
plural int type;
MP_PluralHeap MPPH_var;
#endif
{
plural heap_header header;
plural int new_heap_space;
plural int align;
DBG_CALL("heap_alloc");
DBG_ARGS(fprintf(dbg,"space=????, type=????, MPPH_var=%04x: to_offsets=%04x",MPPH_var,OA_to_offsets(MPPH_var)));
align = type_info_table[type][TYPE_ALIGN];
new_heap_space = heap_space + 1;
new_heap_space = new_heap_space +
(((new_heap_space * sizeof(natural)) % align) / sizeof(natural));
/* new_heap_space is the location where the aligned data will begin */
/* the header will be placed in the previous location, */
if (globalor((plural_space - heap2plural(new_heap_space)) <=
heap2plural(byte2heap(space)+2))) {
fprintf(stderr,"mp_alloc:No Space, trying back end GC\n");
mp_gc();
new_heap_space = heap_space + 1;
new_heap_space = new_heap_space +
(((new_heap_space * sizeof(natural)) % align) / sizeof(natural));
if (globalor((plural_space - heap2plural(new_heap_space)) <=
heap2plural(byte2heap(space)))) {
DBG_FAIL(fprintf(dbg,"FAIL:No Space; p_space=%d, ",plural_space);DBG_PARG("h_space","%04d ",heap_space));
return FAIL;
}
}
/* Initialise header data, store heap offsets for caller,update heap space */
*MPPH_var = new_heap_space-1;
HH_set_space(heap_memory[*MPPH_var],space);
HH_set_free(heap_memory[*MPPH_var],0);
HH_set_info(heap_memory[*MPPH_var],type);
heap_space = new_heap_space + MP_LENGTH(OA_space(MPPH_var));
DBG_EXIT(fprintf(dbg,"SUCCESS"));
return SUCCESS;
}
/*----------------------------------------------------------------------------*
* Function : mp_alloc
*
* Parameters : plural int type: The types of the objects to be
* allocated.
* plural int quantity: This is for giving vector size.
* MP_PluralHeap MPPH_object: MP_PluralHeap object, handle
* on the allocated plural heap space.
*
* Description: Allocates different types and sizes of objects in
* parallel and initialises them all to nil.
*
* Result : int: FAIL/SUCCESS
*---------------------------------------------------------------------------*/
#ifdef __STDC__
int mp_alloc( plural int type, plural int quantity, MP_PluralHeap MPPH_object )
#else
int mp_alloc( type, quantity, MPPH_object )
plural int type;
plural int quantity;
MP_PluralHeap MPPH_object;
#endif
{
plural int size;
plural natural *plural space;
plural int i;
DBG_CALL("mp_alloc");
DBG_ARGS(fprintf(dbg,"type=????,quantity=????,MPPH_object=%04x",MPPH_object));
/* Find sizes of objects being requested */
/* NOTE: this should be done via a table to reduce code length */
if (globalor((type <= 0) || (type >= NUMBER_OF_TYPES))) {
DBG_FAIL(fprintf(dbg,"FAIL: Unknown types"));
return FAIL;
}
size = type_info_table[type][TYPE_SIZE];
/* Allocate space for new objects */
if (heap_alloc((quantity * size), type, MPPH_object) == FAIL) {
DBG_FAIL(fprintf(dbg,"FAIL: Unable to allocate space"));
return FAIL;
}
DBG_EXIT(fprintf(dbg,"SUCCESS"));
return SUCCESS;
}
/*----------------------------------------------------------------------------*
* Function : test
*
* Parameters : MP_PluralHeap MPPH_arg1: Heap objects to test types of
* plural int type: Types we are expecting
* MP_PluralHeap MPPH_result: Boolean result
*
* Description: Returns booleans indicating wether the objects are of the
* type indicated by type.
*
* Result : int FAIL/SUCCESS
*---------------------------------------------------------------------------*/
#ifdef __STDC__
int test( MP_PluralHeap MPPH_arg1, plural int type, MP_PluralHeap MPPH_result )
#else
int test( MPPH_arg1, type, MPPH_result )
MP_PluralHeap MPPH_arg1;
plural int type;
MP_PluralHeap MPPH_result;
#endif
{
plural int boolean;
DBG_CALL("test");
DBG_ARGS(fprintf(dbg,"MPPH_arg1=????, type=????, MPPH_result=????"));
/* if (OA_offsets(MPPH_arg1) == NIL) {
*
* boolean = (NIL == type);
* }
* else {
* Can't tell if it's null by looking at the type and addresss since the
* values overlap now
*/
boolean = OA_info(MPPH_arg1) == type;
if (boolean) OA_offsets(MPPH_result) = NOT_NIL;
else OA_offsets(MPPH_result) = NIL;
DBG_EXIT(fprintf(dbg,"SUCCESS"));
return SUCCESS;
}
/*----------------------------------------------------------------------------*
* Function : eq
*
* Parameters : MP_PluralHeap MPPH_arg1: Handle on plural space of
* MP_PluralHeap MPPH_arg2: objects to be compared
* MP_PluralHeap MPPH_result: Plural space containing
* resulting boolean values.
*
* Description: Compares the objects on the same processors and creates
* a boolean result.
* Integers and floats are equal if their values are the same
* otherwise if the addresses are equal the objects are equal -
* This will need extending when symbols and doubles are added.
*
* Result : int: FAIL/SUCCESS
*---------------------------------------------------------------------------*/
#ifdef __STDC__
int eq( MP_PluralHeap MPPH_arg1, MP_PluralHeap MPPH_arg2,
MP_PluralHeap MPPH_result )
#else
int eq( MPPH_arg1, MPPH_arg2, MPPH_result )
MP_PluralHeap MPPH_arg1;
MP_PluralHeap MPPH_arg2;
MP_PluralHeap MPPH_result;
#endif
{
plural int *plural result;
DBG_CALL("eq");
DBG_ARGS(fprintf(dbg,"MPPH_arg1=????, MPPH_arg2=????, MPPH_arg3=????"));
OA_offsets(MPPH_result) = NIL;
if (OA_offsets(MPPH_arg1) == OA_offsets(MPPH_arg2)) {
OA_offsets(MPPH_result) = NOT_NIL;
}
else if ((OA_offsets(MPPH_arg1)==NIL)||(OA_offsets(MPPH_arg1)==NOT_NIL) ||
(OA_offsets(MPPH_arg2)==NIL)||(OA_offsets(MPPH_arg2)==NOT_NIL)) {
OA_offsets(MPPH_result) = NIL;
}
else if (OA_info(MPPH_arg1) != OA_info(MPPH_arg2)) {
OA_offsets(MPPH_result) = NIL;
}
else if ((OA_info(MPPH_arg1) == INTEGER) ||
(OA_info(MPPH_arg1) == MP_SYMBOL)) {
/* Just compare the bit patterns in affect */
if ((*(plural int *plural) OA_data(MPPH_arg1)) ==
(*(plural int *plural) OA_data(MPPH_arg2)))
OA_offsets(MPPH_result) = NOT_NIL;
}
DBG_EXIT(fprintf(dbg,"SUCCESS"));
return SUCCESS;
}
/* Garbage Collection Rational
* ======= ========== ========
*
* The current garbage collector is designed to work on the back end only,
* there is no need to worry about pointers to the front end as currenmtly
* they cannot be constructed.
* The idea is to half the number of processors and to perform a stop and
* copy operation form one processor set to the idle set and to then resume
* processing on the alternative set. To do this the code must all work in
* terms of the Paired Processor macros (see proc_pair.h).
*
*/
/*----------------------------------------------------------------------------*
* Function : gc
*
* Parameters : MP_PluralHeap MPPH_objects: This is a parallel lisp object
* to be (recursively) copied
* to the alternative processor
* set
*
* Description: What the function does should go here. The problem of
* justification
*
* Result : MP_PluralHeap: the new position of the objects
*---------------------------------------------------------------------------*/
#ifdef __STDC__
plural natural gc( plural natural offsets )
#else
plural natural gc( offsets )
plural natural offsets;
#endif
{
plural natural *plural general_vector;
plural natural size, align;
plural natural result_offset;
plural heap_header headers;
plural heap_header data;
plural natural this_heap_space;
plural int i;
DBG_CALL("gc");
DBG_ARGS(DBG_PARG("PP_iproc","%d ",PP_iproc);DBG_PARG(" \noffsets","%d ",offsets));
/* The active set on entry to the function will be pairs of processors,
* that is for each gcing processor which is active, its associated
* pair-processor is also active.
*/
PP_on_set() PP_push_to(offsets, offsets);
if ((offsets == NIL) || (offsets == NOT_NIL)) {
result_offset = offsets; /* These special objects */
DBG_EXIT(DBG_PARG("","%d ",result_offset));
return result_offset; /* are represented by a
* special offset, so we
* merely copy this offset
*/
}
PP_on_set() {
headers = heap_memory[offsets]; /* get headers */
PP_push_to(headers, headers); /* duplicate in paired PE
* this will mean the PES
* get activated in pairs
*/
}
if (HH_gced_p(headers)) { /* already gced the offset of the
* object on the `off' PE is held
* on the `on' PE in the header,
* copy this offset
*/
PP_on_set() PP_push_to(result_offset, HH_gcto(headers));
DEBUG(DBG_PARG("Extracted forward address","%d ",headers));
DBG_EXIT(DBG_PARG("","%d ",result_offset));
return result_offset;
}
/* PP_off_set() {
*
* result_offset = heap_space;
* PP_push_to(result_offset, result_offset);
* heap_memory[heap_space++] = headers;
* }
* PP_on_set() HH_gc_moved(heap_memory[offsets],result_offset);
*/
/* Deal with the header: Increament heap_space, it now is the position where
* the data starts and the header goes in the previous slot. munge the heap
* space to allow for alignment if required. result_offset, is where the
* header is (i.e. heap_space - 1) and we leave the forwarding address
*/
PP_off_set() ++heap_space;
switch (HH_info(headers)) {
case MP_SYMBOL:
case MP_FLOAT:
case INTEGER:
align = type_info_table[HH_info(headers)][TYPE_ALIGN];
PP_off_set() heap_space = heap_space +(((heap_space * sizeof(natural)) %
align) / sizeof(natural));
default:
PP_off_set() heap_memory[(result_offset = heap_space-1)] = headers;
PP_on_set() {
PP_pull_to(result_offset,result_offset);
HH_gc_moved(heap_memory[offsets],result_offset);
}
}
switch (HH_info(headers)) {
case MP_SYMBOL:
case MP_FLOAT : /* Just copy the 4-byte bit pattern across */
case INTEGER :
size = MP_LENGTH(type_info_table[HH_info(headers)][TYPE_SIZE]);
for (i=1; i<=size; i++) { /* We have to swap between active sets since
* an operation has to be preformed on both
* PEs as well as the Xnet assignment
*/
PP_on_set() data = heap_memory[offsets + i];
PP_off_set() PP_pull_to(heap_memory[heap_space++],data);
}
break;
case MP_VECTOR : /* These contain objects so we have to */
case MP_CONS : /* call gc again to copy them
* across. The result is the new address
* in the `off' set of PEs.
*/
size = MP_LENGTH(HH_space(headers)); /* reserve space for object */
PP_off_set() heap_space=heap_space+size;
general_vector = (plural natural *plural) (heap_memory + offsets + 1);
for (i = 0; i<size; i++) { /* Note: Pairs of active processors still */
data = (plural heap_header) gc(general_vector[i]);
PP_off_set() heap_memory[result_offset+i+1]=data;
}
break;
}
DBG_EXIT(DBG_PARG("","%d ",result_offset));
return result_offset;
}
/*----------------------------------------------------------------------------*
* Function : mp_gc
*
* Parameters : none
*
* Description: Garbage collects the system, this involves following all the
* heap roots in the plural space and copying them to the
* `off' processor set. The active memory will be contiguous
* and garbage will have been lost. The `off' set becomes the
* `on' set.
*
* Result : void
*---------------------------------------------------------------------------*/
#ifdef __STDC__
visible void mp_gc( void )
#else
visible void mp_gc( )
#endif
{
int i;
plural int retrieved;
plural natural new_offsets;
plural natural gc_root;
int old_debug_status=debug_status;
DBG_CALL("mp_gc");
DBG_ARGS(fprintf(dbg,"void"));
PP_on_set() retrieved = heap_space;
DBG_OFF();
all {
PP_off_set() heap_space = NOT_NIL + MP_LENGTH(sizeof(heap_header) +
type_info_table[MP_SYMBOL][TYPE_SIZE]);
for (i = TOP; i>plural_space; i--) {
/* First copy the data across, if this is not actually a pointer we need
* to do this any way. It also means we can activate the processors in
* pairs when we examine the contents of the slot. This is necessary for
* the calls to gc.
*/
PP_on_set() PP_push_to(plural_memory[i],plural_memory[i]);
if (!(plural_memory[i] & FREE_FLAG)) { /* Not free memory so gc it. The
* value of gc for the `off'
* set is where the `on' objects
* were copied to. The `on'
* value is not important.
*/
plural_memory[i] = gc( plural_memory[i] );
}
}
/* Because we may have gced in the middle of doing something we may have
* handles on heap stuff which are not reachable from the plural space.
* We instigate a gc for each of the varibales on the gc protect stack
*/
fprintf(stderr,"mp_gc debug: %d gc protect roots\n",next_gc_root);
for (i=0;i<next_gc_root;i++) {
gc_root = *gc_roots[i];
PP_on_set() PP_push_to(gc_root,gc_root);
if (!(gc_root & FREE_FLAG)) gc_root = gc( gc_root );
PP_on_set() PP_pull_to(gc_root,gc_root);
*gc_roots[i] = gc_root;
}
/* Now we have to copy the gumpf back, the starting active set is
* the even processors so we are copying from the offset, leftwards
*/
PP_off_set() {
pp_xsend(0,-1,(plural char *plural) heap_memory,
(plural char *plural) heap_memory, MEMORY_SIZE_IN_BYTES);
PP_push_to(heap_space,heap_space);
}
}
debug_status=old_debug_status;
/* Some More Debugging Info */
PP_on_set() {
retrieved = retrieved - heap_space;
fprintf(stderr,"Top-Level=%s, some stats:\n",gc_message);
DBG_PVAR(stderr,"Retrieved","%04d ",retrieved);
DBG_PVAR(stderr,"\nHeap Top ","%04d ",heap_space);
fprintf(stderr,"\n");
}
DBG_OFF();
DBG_EXIT(fprintf(dbg,"void"));
}